{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook is a simple model of traffic. It doesn't include cases such as bad drivers or accidents. It only deals with one lane. The point is to build the simplest model possible to observe those times when traffic jams happen for no apparent reason. \n",
    "\n",
    "We are going to do this using the Nagel–Schreckenberg model, developed by two German physicists."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. If the velocity is below vmax, it increases by one unit. Drivers usually increase their speed if they are below the speed limit and have appropriate room.\n",
    "\n",
    "2. We check the distance between the car and the car in front of it. There are d spaces in between the car and the car in front of it. If the car's velocity v is greater than or equal to d, then it adjusts it's speed to d-1 so it won't collide. \n",
    "\n",
    "3. Now we throw in some randomness to account for driver behavior. This is the part that makes it Monte Carlo-esque. If the velocity is positive, than with probability p we will reduce the velocity by 1 unit.\n",
    "\n",
    "4. The car moves ahead by v units."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A few notes - \n",
    "     - we can compare v and d because each iteration of the model occurs within one time unit. For example, if our velocity were in meters per second, since each iteration occurs within one second, the velocity is directly comparable to the distance, as if they were both in meters.\n",
    "     \n",
    "     - Adjusting p can yield totally different kinds of models. A high p-value will cause a lot of random traffic jams, whereas a low one will result in a smoother drive."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class Car:\n",
    "    def __init__(self):\n",
    "        self.velocity = 0\n",
    "        self.position = 0\n",
    "        self.speeds = []\n",
    "        self.places = []\n",
    "    \n",
    "    def setVelocity(self, v):            # a negative value will slow the car down\n",
    "        self.velocity = v\n",
    "        \n",
    "    def getVelocity(self):\n",
    "        return self.velocity\n",
    "        \n",
    "    def getPos(self):\n",
    "        return self.position\n",
    "     \n",
    "    def resetPos(self):                # the cars are on a circular track\n",
    "        self.position = 0\n",
    "    \n",
    "    def moveUp(self): \n",
    "        self.places.append(self.position)      # I want to be able to visualize the data in some way later \n",
    "        self.speeds.append(self.velocity)\n",
    "        self.position += self.velocity\n",
    "        \n",
    "    def showHistory(self):\n",
    "        print(self.places)\n",
    "        \n",
    "    def getPlaces(self):\n",
    "        return self.places\n",
    "    \n",
    "    def getSpeeds(self):\n",
    "        return self.speeds"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import random\n",
    "\n",
    "class Road:\n",
    "    def __init__(self, speedLimit, prob, cells):\n",
    "        self.road = []\n",
    "        self.speedLimit = speedLimit\n",
    "        self.prob = prob                  # the probability p in step 3\n",
    "        self.cells = cells\n",
    "        \n",
    "    def addCar(self, car):\n",
    "        self.road.append(car)\n",
    "        \n",
    "    def getCars(self):\n",
    "        return self.road\n",
    "    \n",
    "    def getLimit(self):\n",
    "        return self.speedLimit\n",
    "        \n",
    "    def increaseOne(self, ind):                 # Step 1\n",
    "        car = self.road[ind]\n",
    "        return min(car.getVelocity()+1, self.getLimit())\n",
    "    \n",
    "    def getDistance(self, carA, carB):                # carA has to be behind carB.\n",
    "        return carB.getPos() - carA.getPos()\n",
    "    \n",
    "    def adjustVelocity(self, ind1, ind2):               # carA is the car being updated! This is Step 2\n",
    "        carA = self.road[ind1]\n",
    "        carB = self.road[ind2]\n",
    "        v = min(self.getDistance(carA, carB)-1, carA.getVelocity())\n",
    "        v = max(v, 0)\n",
    "        return v\n",
    "    \n",
    "    def someRandomness(self, ind):              # Step 3\n",
    "        car = self.road[ind]\n",
    "        v = car.getVelocity()\n",
    "        if (random.random() < self.prob) and v > 1:\n",
    "            v -= 1\n",
    "        return v\n",
    "    \n",
    "    def update(self, ind, v):\n",
    "        car = self.road[ind]\n",
    "        car.setVelocity(v)\n",
    "    \n",
    "    def moveCar(self, ind, v):\n",
    "        car = self.road[ind]\n",
    "        car.setVelocity(v)\n",
    "        car.moveUp()\n",
    "    \n",
    "    def show(self):\n",
    "        print(\"Cars = \", len(self.road), \"\\n\", \"spaces = \", self.cells, \"\\n\", \"speed limit = \", self.speedLimit, \"\\n\", \"p = \", self.prob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cars =  50 \n",
      " spaces =  60 \n",
      " speed limit =  5 \n",
      " p =  0.5\n"
     ]
    }
   ],
   "source": [
    "monteCarlo = Road(5, .5, 60)        # a speed limit of 10 and a probability of .3\n",
    "\n",
    "for i in range(50):\n",
    "    temp = Car()\n",
    "    monteCarlo.addCar(temp)\n",
    "    \n",
    "monteCarlo.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Ok now let's actually run the model.\n",
    "\n",
    "for i in range(200):\n",
    "    for j in range(len(monteCarlo.getCars())):\n",
    "        v = monteCarlo.increaseOne(j)                       # step 1\n",
    "        monteCarlo.update(j, v)\n",
    "#         print(\"v = \", v)                   # for debugging purposes\n",
    "        \n",
    "        if j != 0: v = monteCarlo.adjustVelocity(j, j-1)       # step 2\n",
    "        monteCarlo.update(j, v)\n",
    "#         print(\"v2 = \", v)\n",
    "            \n",
    "        v = monteCarlo.someRandomness(j)\n",
    "        monteCarlo.update(j, v)\n",
    "#         print(\"v3 = \", v)\n",
    "        \n",
    "        monteCarlo.moveCar(j, v)\n",
    "#         print(\"done\", \"\\n\")\n",
    "#     print(\"new round\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "50\n",
      "[[  0   0   0 ...,   0   0   0]\n",
      " [  1   0   0 ...,   0   0   0]\n",
      " [  3   1   0 ...,   0   0   0]\n",
      " ..., \n",
      " [885 871 861 ..., 497 495 490]\n",
      " [890 876 866 ..., 502 499 494]\n",
      " [895 880 871 ..., 506 503 498]]\n"
     ]
    }
   ],
   "source": [
    "# now let's look at the results and see what we need to adjust.\n",
    "import numpy as np\n",
    "places = []\n",
    "speeds = []\n",
    "\n",
    "\n",
    "\n",
    "for i in monteCarlo.getCars():\n",
    "    places.append(i.getPlaces())\n",
    "    speeds.append(i.getSpeeds())\n",
    "\n",
    "print(len(places))      # each column represents a car, the rows represent time.\n",
    "\n",
    "pl = np.asarray(places)\n",
    "pl = pl.transpose()\n",
    "\n",
    "sp = np.asarray(speeds)\n",
    "sp = sp.transpose()\n",
    "\n",
    "print(pl)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(200, 50)"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pl.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Each column in pl represents a car. Each row represents an iteration, or a passing of time.\n",
    "# now I'm going to make a dictionary so I can put it into a pandas dataframe easily\n",
    "\n",
    "dataPlaces = {}\n",
    "\n",
    "for i in range(50):\n",
    "    dataPlaces[i] = pl[:,i]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "dataSpeeds = {}\n",
    "\n",
    "for i in range(50):\n",
    "    dataSpeeds[i] = sp[:,i]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>0</th>\n",
       "      <th>1</th>\n",
       "      <th>2</th>\n",
       "      <th>3</th>\n",
       "      <th>4</th>\n",
       "      <th>5</th>\n",
       "      <th>6</th>\n",
       "      <th>7</th>\n",
       "      <th>8</th>\n",
       "      <th>9</th>\n",
       "      <th>...</th>\n",
       "      <th>40</th>\n",
       "      <th>41</th>\n",
       "      <th>42</th>\n",
       "      <th>43</th>\n",
       "      <th>44</th>\n",
       "      <th>45</th>\n",
       "      <th>46</th>\n",
       "      <th>47</th>\n",
       "      <th>48</th>\n",
       "      <th>49</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>6</td>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>10</td>\n",
       "      <td>5</td>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>...</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>5 rows × 50 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "   0   1   2   3   4   5   6   7   8   9  ...  40  41  42  43  44  45  46  47  \\\n",
       "0   0   0   0   0   0   0   0   0   0   0 ...   0   0   0   0   0   0   0   0   \n",
       "1   1   0   0   0   0   0   0   0   0   0 ...   0   0   0   0   0   0   0   0   \n",
       "2   3   1   0   0   0   0   0   0   0   0 ...   0   0   0   0   0   0   0   0   \n",
       "3   6   3   1   0   0   0   0   0   0   0 ...   0   0   0   0   0   0   0   0   \n",
       "4  10   5   2   1   0   0   0   0   0   0 ...   0   0   0   0   0   0   0   0   \n",
       "\n",
       "   48  49  \n",
       "0   0   0  \n",
       "1   0   0  \n",
       "2   0   0  \n",
       "3   0   0  \n",
       "4   0   0  \n",
       "\n",
       "[5 rows x 50 columns]"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "places = pd.DataFrame(dataPlaces)\n",
    "speeds = pd.DataFrame(dataSpeeds)\n",
    "\n",
    "places.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# now let's put them into a csv so I can visualize them with R\n",
    "\n",
    "places.to_csv(\"Places2.csv\")\n",
    "speeds.to_csv(\"Speeds2.csv\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Fow now, that concludes this part. I might be back here to actually make use of the circular track \n",
    "# that it's supposed to have, or to do something a bit more complicated. But for now I need to visualize this data."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.4.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
